import { Vec3 } from '@/core/types';

export interface AudioConfig {
  masterVolume: number;
  soundVolume: number;
  musicVolume: number;
  enabled: boolean;
}

export interface Sound3D {
  id: string;
  buffer: AudioBuffer;
  position?: Vec3;
  volume: number;
  loop: boolean;
  source?: AudioBufferSourceNode;
  gainNode?: GainNode;
  pannerNode?: PannerNode;
}

export class AudioManager {
  private audioContext!: AudioContext;
  private sounds: Map<string, AudioBuffer> = new Map();
  private activeSounds: Map<string, Sound3D> = new Map();
  private masterGainNode!: GainNode;
  private soundGainNode!: GainNode;
  private musicGainNode!: GainNode;
  private config: AudioConfig;
  private initialized = false;
  private currentMusic: Sound3D | null = null;
  private musicFadeTimer: number = 0;
  private musicFadeDuration: number = 2.0; // 2秒淡入淡出
  private listenerPosition: Vec3 = { x: 0, y: 0, z: 0 };

  constructor() {
    this.config = {
      masterVolume: 0.7,
      soundVolume: 1.0,
      musicVolume: 0.8,
      enabled: true
    };

    // 延迟初始化，等待用户交互
    this.initializeAudio();
    this.setupUserInteractionListener();
  }

  private setupUserInteractionListener(): void {
    const handleUserInteraction = async () => {
      console.log('User interaction detected, ensuring audio context is ready');
      await this.ensureInitialized();
      
      // 移除事件监听器，只需要一次用户交互
      document.removeEventListener('click', handleUserInteraction);
      document.removeEventListener('keydown', handleUserInteraction);
      document.removeEventListener('touchstart', handleUserInteraction);
    };

    // 监听各种用户交互事件
    document.addEventListener('click', handleUserInteraction);
    document.addEventListener('keydown', handleUserInteraction);
    document.addEventListener('touchstart', handleUserInteraction);
  }

  private async initializeAudio(): Promise<void> {
    try {
      // 创建音频上下文
      this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
      
      // 创建主增益节点
      this.masterGainNode = this.audioContext.createGain();
      this.masterGainNode.connect(this.audioContext.destination);
      this.masterGainNode.gain.value = this.config.masterVolume;

      // 创建音效增益节点
      this.soundGainNode = this.audioContext.createGain();
      this.soundGainNode.connect(this.masterGainNode);
      this.soundGainNode.gain.value = this.config.soundVolume;

      // 创建音乐增益节点
      this.musicGainNode = this.audioContext.createGain();
      this.musicGainNode.connect(this.masterGainNode);
      this.musicGainNode.gain.value = this.config.musicVolume;

      // 设置3D音频监听器
      if (this.audioContext.listener) {
        this.audioContext.listener.setPosition(0, 0, 0);
        this.audioContext.listener.setOrientation(0, 0, -1, 0, 1, 0);
      }

      this.initialized = true;
      console.log('Audio system initialized');
    } catch (error) {
      console.error('Failed to initialize audio system:', error);
      this.config.enabled = false;
    }
  }

  public async ensureInitialized(): Promise<void> {
    if (!this.initialized && this.config.enabled) {
      await this.initializeAudio();
    }

    // 恢复音频上下文（如果被暂停）
    if (this.audioContext && this.audioContext.state === 'suspended') {
      try {
        await this.audioContext.resume();
        console.log('Audio context resumed');
      } catch (error) {
        console.error('Failed to resume audio context:', error);
      }
    }
  }

  public async loadSound(id: string, url: string): Promise<boolean> {
    if (!this.config.enabled) return false;

    try {
      await this.ensureInitialized();
      
      // 尝试加载真实音频文件
      try {
        const response = await fetch(url);
        const arrayBuffer = await response.arrayBuffer();
        const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
        
        this.sounds.set(id, audioBuffer);
        console.log(`Loaded sound: ${id}`);
        return true;
      } catch (fetchError) {
        // 如果加载失败，生成程序化音频
        console.warn(`Failed to load ${id} from ${url}, generating fallback audio`);
        const fallbackBuffer = this.generateFallbackAudio(id);
        if (fallbackBuffer) {
          this.sounds.set(id, fallbackBuffer);
          console.log(`Generated fallback audio for: ${id}`);
          return true;
        }
      }
      
      return false;
    } catch (error) {
      console.error(`Failed to load sound ${id}:`, error);
      return false;
    }
  }

  private generateFallbackAudio(soundId: string): AudioBuffer | null {
    if (!this.audioContext) return null;

    try {
      let duration = 1.0; // 默认1秒
      let frequency = 440; // 默认A4音符
      let waveType: OscillatorType = 'sine';

      // 根据音效类型生成不同的音频
      if (soundId.includes('block_break')) {
        duration = 0.3;
        frequency = 200 + Math.random() * 300;
        waveType = 'square';
      } else if (soundId.includes('block_place')) {
        duration = 0.2;
        frequency = 300 + Math.random() * 200;
        waveType = 'triangle';
      } else if (soundId.includes('footstep')) {
        duration = 0.15;
        frequency = 100 + Math.random() * 100;
        waveType = 'sawtooth';
      } else if (soundId.includes('jump')) {
        duration = 0.4;
        frequency = 400;
        waveType = 'sine';
      } else if (soundId.includes('music')) {
        duration = 30.0; // 30秒的音乐循环
        frequency = 220; // 低音A
        waveType = 'sine';
      } else if (soundId.includes('idle') || soundId.includes('hurt')) {
        duration = 0.5;
        frequency = 150 + Math.random() * 200;
        waveType = 'triangle';
      }

      const sampleRate = this.audioContext.sampleRate;
      const buffer = this.audioContext.createBuffer(1, duration * sampleRate, sampleRate);
      const data = buffer.getChannelData(0);

      if (soundId.includes('music')) {
        // 生成简单的和弦音乐
        this.generateMusicBuffer(data, sampleRate, duration);
      } else {
        // 生成简单的音效
        this.generateSoundBuffer(data, sampleRate, duration, frequency, waveType);
      }

      return buffer;
    } catch (error) {
      console.error(`Failed to generate fallback audio for ${soundId}:`, error);
      return null;
    }
  }

  private generateSoundBuffer(
    data: Float32Array, 
    sampleRate: number, 
    duration: number, 
    frequency: number, 
    waveType: OscillatorType
  ): void {
    const samples = data.length;
    
    for (let i = 0; i < samples; i++) {
      const t = i / sampleRate;
      const envelope = Math.exp(-t * 3); // 指数衰减包络
      
      let sample = 0;
      switch (waveType) {
        case 'sine':
          sample = Math.sin(2 * Math.PI * frequency * t);
          break;
        case 'square':
          sample = Math.sign(Math.sin(2 * Math.PI * frequency * t));
          break;
        case 'triangle':
          sample = (2 / Math.PI) * Math.asin(Math.sin(2 * Math.PI * frequency * t));
          break;
        case 'sawtooth':
          sample = 2 * (t * frequency - Math.floor(t * frequency + 0.5));
          break;
      }
      
      data[i] = sample * envelope * 0.3; // 降低音量
    }
  }

  private generateMusicBuffer(data: Float32Array, sampleRate: number, duration: number): void {
    const samples = data.length;
    
    // 简单的和弦进行：C - Am - F - G
    const chords = [
      [261.63, 329.63, 392.00], // C major
      [220.00, 261.63, 329.63], // A minor
      [174.61, 220.00, 261.63], // F major
      [196.00, 246.94, 293.66]  // G major
    ];
    
    const chordDuration = duration / 4; // 每个和弦持续1/4的总时长
    
    for (let i = 0; i < samples; i++) {
      const t = i / sampleRate;
      const chordIndex = Math.floor(t / chordDuration) % chords.length;
      const chord = chords[chordIndex];
      
      let sample = 0;
      // 混合和弦中的所有音符
      for (const freq of chord) {
        sample += Math.sin(2 * Math.PI * freq * t) * 0.2;
      }
      
      // 添加简单的包络和混响效果
      const envelope = 0.5 + 0.5 * Math.sin(2 * Math.PI * t / chordDuration);
      data[i] = sample * envelope * 0.1; // 保持音乐音量较低
    }
  }

  public async loadAudioAssets(): Promise<void> {
    if (!this.config.enabled) return;

    const soundAssets = [
      // 方块音效
      { id: 'block_break_stone', url: '/assets/sounds/block_break_stone.ogg' },
      { id: 'block_break_wood', url: '/assets/sounds/block_break_wood.ogg' },
      { id: 'block_break_dirt', url: '/assets/sounds/block_break_dirt.ogg' },
      { id: 'block_place', url: '/assets/sounds/block_place.ogg' },
      
      // 玩家音效
      { id: 'footstep_stone', url: '/assets/sounds/footstep_stone.ogg' },
      { id: 'footstep_dirt', url: '/assets/sounds/footstep_dirt.ogg' },
      { id: 'jump', url: '/assets/sounds/jump.ogg' },
      
      // 生物音效
      { id: 'cow_idle', url: '/assets/sounds/cow_idle.ogg' },
      { id: 'pig_idle', url: '/assets/sounds/pig_idle.ogg' },
      { id: 'sheep_idle', url: '/assets/sounds/sheep_idle.ogg' },
      { id: 'zombie_idle', url: '/assets/sounds/zombie_idle.ogg' },
      { id: 'zombie_hurt', url: '/assets/sounds/zombie_hurt.ogg' },
      { id: 'skeleton_idle', url: '/assets/sounds/skeleton_idle.ogg' },
      { id: 'bow_shoot', url: '/assets/sounds/bow_shoot.ogg' },
      
      // 背景音乐 - 基础轨道
      { id: 'music_calm', url: '/assets/music/calm.ogg' },
      { id: 'music_creative', url: '/assets/music/creative.ogg' },
      { id: 'music_peaceful', url: '/assets/music/peaceful.ogg' },
      { id: 'music_ambient', url: '/assets/music/ambient.ogg' },
      
      // 背景音乐 - 夜晚和紧张
      { id: 'music_night', url: '/assets/music/night.ogg' },
      { id: 'music_tense', url: '/assets/music/tense.ogg' },
      { id: 'music_mysterious', url: '/assets/music/mysterious.ogg' },
      { id: 'music_dramatic', url: '/assets/music/dramatic.ogg' },
      
      // 背景音乐 - 冒险和生存
      { id: 'music_adventure', url: '/assets/music/adventure.ogg' },
      { id: 'music_survival', url: '/assets/music/survival.ogg' },
      
      // 背景音乐 - 环境特殊
      { id: 'music_cave', url: '/assets/music/cave.ogg' },
      { id: 'music_underground', url: '/assets/music/underground.ogg' },
      { id: 'music_sky', url: '/assets/music/sky.ogg' },
      { id: 'music_ethereal', url: '/assets/music/ethereal.ogg' }
    ];

    // 并行加载所有音频资源
    const loadPromises = soundAssets.map(asset => 
      this.loadSound(asset.id, asset.url).catch(error => {
        console.warn(`Failed to load ${asset.id}, using fallback`);
        return false;
      })
    );

    await Promise.all(loadPromises);
    console.log('Audio assets loading completed');
  }

  public playSound(soundId: string, options: {
    position?: Vec3;
    volume?: number;
    loop?: boolean;
    pitch?: number;
  } = {}): string | null {
    if (!this.config.enabled) {
      console.log(`Audio disabled, not playing sound: ${soundId}`);
      return null;
    }
    
    if (!this.initialized) {
      console.log(`Audio not initialized, not playing sound: ${soundId}`);
      return null;
    }

    const buffer = this.sounds.get(soundId);
    if (!buffer) {
      console.warn(`Sound not found: ${soundId}. Available sounds:`, Array.from(this.sounds.keys()));
      return null;
    }

    console.log(`Playing sound: ${soundId} with options:`, options);

    try {
      const soundInstanceId = `${soundId}_${Date.now()}_${Math.random()}`;
      
      // 创建音频源
      const source = this.audioContext.createBufferSource();
      source.buffer = buffer;
      source.loop = options.loop || false;

      // 创建增益节点
      const gainNode = this.audioContext.createGain();
      gainNode.gain.value = (options.volume || 1.0) * this.config.soundVolume;

      let finalNode: AudioNode = gainNode;

      // 如果有位置信息，创建3D音频
      let pannerNode: PannerNode | undefined;
      if (options.position) {
        pannerNode = this.audioContext.createPanner();
        pannerNode.panningModel = 'HRTF';
        pannerNode.distanceModel = 'inverse';
        pannerNode.refDistance = 1;
        pannerNode.maxDistance = 50;
        pannerNode.rolloffFactor = 1;
        pannerNode.coneInnerAngle = 360;
        pannerNode.coneOuterAngle = 0;
        pannerNode.coneOuterGain = 0;

        // 设置3D位置
        pannerNode.setPosition(
          options.position.x,
          options.position.y,
          options.position.z
        );

        gainNode.connect(pannerNode);
        pannerNode.connect(this.soundGainNode);
        finalNode = pannerNode;
      } else {
        gainNode.connect(this.soundGainNode);
      }

      // 连接音频图
      source.connect(gainNode);

      // 应用音调变化
      if (options.pitch && options.pitch !== 1.0) {
        source.playbackRate.value = options.pitch;
      }

      // 存储音频实例
      const sound3D: Sound3D = {
        id: soundInstanceId,
        buffer,
        position: options.position,
        volume: options.volume || 1.0,
        loop: options.loop || false,
        source,
        gainNode,
        pannerNode
      };

      this.activeSounds.set(soundInstanceId, sound3D);

      // 设置结束回调
      source.onended = () => {
        this.activeSounds.delete(soundInstanceId);
      };

      // 播放音频
      source.start();

      return soundInstanceId;
    } catch (error) {
      console.error(`Failed to play sound ${soundId}:`, error);
      return null;
    }
  }

  public stopSound(soundInstanceId: string): void {
    const sound = this.activeSounds.get(soundInstanceId);
    if (sound && sound.source) {
      try {
        sound.source.stop();
        this.activeSounds.delete(soundInstanceId);
      } catch (error) {
        console.error('Failed to stop sound:', error);
      }
    }
  }

  public stopAllSounds(): void {
    for (const [id, sound] of this.activeSounds) {
      if (sound.source) {
        try {
          sound.source.stop();
        } catch (error) {
          console.error('Failed to stop sound:', error);
        }
      }
    }
    this.activeSounds.clear();
  }

  public playMusic(musicId: string, loop: boolean = true, fadeIn: boolean = true): string | null {
    if (!this.config.enabled || !this.initialized) return null;

    const buffer = this.sounds.get(musicId);
    if (!buffer) {
      console.warn(`Music not found: ${musicId}`);
      return null;
    }

    try {
      // 如果有当前音乐，先淡出
      if (this.currentMusic) {
        this.fadeOutCurrentMusic();
      }

      // 创建新的音乐源
      const source = this.audioContext.createBufferSource();
      source.buffer = buffer;
      source.loop = loop;

      // 创建音乐专用的增益节点
      const musicGainNode = this.audioContext.createGain();
      
      // 如果需要淡入，从0开始
      if (fadeIn) {
        musicGainNode.gain.value = 0;
        // 在接下来的2秒内淡入到目标音量
        musicGainNode.gain.linearRampToValueAtTime(
          this.config.musicVolume,
          this.audioContext.currentTime + this.musicFadeDuration
        );
      } else {
        musicGainNode.gain.value = this.config.musicVolume;
      }

      // 连接音频图
      source.connect(musicGainNode);
      musicGainNode.connect(this.masterGainNode);

      const musicInstanceId = `music_${musicId}_${Date.now()}`;
      const musicSound: Sound3D = {
        id: musicInstanceId,
        buffer,
        volume: 1.0,
        loop,
        source,
        gainNode: musicGainNode
      };

      // 设置结束回调
      source.onended = () => {
        if (this.currentMusic?.id === musicInstanceId) {
          this.currentMusic = null;
        }
        this.activeSounds.delete(musicInstanceId);
      };

      // 播放音乐
      source.start();

      // 更新当前音乐引用
      this.currentMusic = musicSound;
      this.activeSounds.set(musicInstanceId, musicSound);

      console.log(`Started playing music: ${musicId}`);
      return musicInstanceId;
    } catch (error) {
      console.error(`Failed to play music ${musicId}:`, error);
      return null;
    }
  }

  private fadeOutCurrentMusic(): void {
    if (!this.currentMusic || !this.currentMusic.gainNode) return;

    try {
      // 在接下来的2秒内淡出到0
      this.currentMusic.gainNode.gain.linearRampToValueAtTime(
        0,
        this.audioContext.currentTime + this.musicFadeDuration
      );

      // 2秒后停止音乐
      setTimeout(() => {
        if (this.currentMusic && this.currentMusic.source) {
          try {
            this.currentMusic.source.stop();
          } catch (error) {
            console.error('Failed to stop faded music:', error);
          }
        }
      }, this.musicFadeDuration * 1000);
    } catch (error) {
      console.error('Failed to fade out music:', error);
    }
  }

  public stopMusic(fadeOut: boolean = true): void {
    if (this.currentMusic) {
      if (fadeOut) {
        this.fadeOutCurrentMusic();
      } else {
        try {
          if (this.currentMusic.source) {
            this.currentMusic.source.stop();
          }
        } catch (error) {
          console.error('Failed to stop music:', error);
        }
      }
      this.currentMusic = null;
    }

    // 清理所有音乐实例
    for (const [id, sound] of this.activeSounds) {
      if (id.startsWith('music_') && sound.source) {
        try {
          if (!fadeOut) {
            sound.source.stop();
          }
          this.activeSounds.delete(id);
        } catch (error) {
          console.error('Failed to stop music:', error);
        }
      }
    }
  }

  public getCurrentMusic(): Sound3D | null {
    return this.currentMusic;
  }

  public isMusicPlaying(): boolean {
    return this.currentMusic !== null;
  }

  public crossFadeMusic(newMusicId: string, loop: boolean = true): string | null {
    // 交叉淡入淡出：新音乐淡入的同时旧音乐淡出
    return this.playMusic(newMusicId, loop, true);
  }

  public setMusicFadeDuration(duration: number): void {
    this.musicFadeDuration = Math.max(0.1, Math.min(10, duration)); // 限制在0.1-10秒之间
  }

  public getMusicFadeDuration(): number {
    return this.musicFadeDuration;
  }

  public setMasterVolume(volume: number): void {
    this.config.masterVolume = Math.max(0, Math.min(1, volume));
    if (this.masterGainNode) {
      this.masterGainNode.gain.value = this.config.masterVolume;
    }
  }

  public setSoundVolume(volume: number): void {
    this.config.soundVolume = Math.max(0, Math.min(1, volume));
    if (this.soundGainNode) {
      this.soundGainNode.gain.value = this.config.soundVolume;
    }
  }

  public setMusicVolume(volume: number): void {
    this.config.musicVolume = Math.max(0, Math.min(1, volume));
    if (this.musicGainNode) {
      this.musicGainNode.gain.value = this.config.musicVolume;
    }
  }

  public updateListenerPosition(position: Vec3, forward: Vec3, up: Vec3): void {
    this.listenerPosition = { ...position };
    
    if (this.audioContext && this.audioContext.listener) {
      try {
        this.audioContext.listener.setPosition(position.x, position.y, position.z);
        this.audioContext.listener.setOrientation(
          forward.x, forward.y, forward.z,
          up.x, up.y, up.z
        );
      } catch (error) {
        console.error('Failed to update listener position:', error);
      }
    }
  }

  public updateSoundPosition(soundInstanceId: string, position: Vec3): void {
    const sound = this.activeSounds.get(soundInstanceId);
    if (sound && sound.pannerNode) {
      sound.position = { ...position };
      sound.pannerNode.setPosition(position.x, position.y, position.z);
    }
  }

  public getConfig(): AudioConfig {
    return { ...this.config };
  }

  public setEnabled(enabled: boolean): void {
    this.config.enabled = enabled;
    if (!enabled) {
      this.stopAllSounds();
    }
  }

  public isEnabled(): boolean {
    return this.config.enabled;
  }

  public getActiveSoundCount(): number {
    return this.activeSounds.size;
  }

  public dispose(): void {
    this.stopAllSounds();
    
    if (this.audioContext) {
      this.audioContext.close();
    }
    
    this.sounds.clear();
    this.activeSounds.clear();
  }
}

// 单例实例
let audioManagerInstance: AudioManager | null = null;

export function getAudioManager(): AudioManager {
  if (!audioManagerInstance) {
    audioManagerInstance = new AudioManager();
  }
  return audioManagerInstance;
}